﻿using AutoRevit.Utils;

namespace Autodesk.Revit.UI.Selection;

/// <summary>
/// Autodesk.Revit.UI.Selection.Selection 的扩展方法
/// </summary>
public static class SelectionExtensions
{
    //private static readonly SynchronizationContext _mainThreadSynContext;

    //static SelectionExtensions()
    //{
    //    _mainThreadSynContext = SynchronizationContext.Current;
    //}

    /// <summary>
    /// 是否选择中
    /// </summary>
    public static bool IsSelection { get; private set; }

    #region object单选

    /// <summary>
    /// 尝试选择单个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObject(this Selection selection, ObjectType objectType, out Reference reference)
    {
        reference = null!;

        IsSelection = true;

        try
        {
            reference = selection.PickObject(objectType);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return reference != null;
    }

    /// <summary>
    /// 尝试选择单个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObject(this Selection selection, ObjectType objectType, string statusPrompt, out Reference reference)
    {
        reference = null!;

        IsSelection = true;

        try
        {
            reference = selection.PickObject(objectType, statusPrompt);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return reference != null;
    }

    /// <summary>
    /// 尝试选择单个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObject(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, out Reference reference)
    {
        reference = null!;

        IsSelection = true;

        try
        {
            reference = selection.PickObject(objectType, selectionFilter);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return reference != null;
    }

    /// <summary>
    /// 尝试选择单个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObject(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, string statusPrompt, out Reference reference)
    {
        reference = null!;

        IsSelection = true;

        try
        {
            reference = selection.PickObject(objectType, selectionFilter, statusPrompt);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return reference != null;
    }


    /// <summary>
    /// 尝试选择一个点
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryPickPoint(this Selection selection, out XYZ point)
    {
        point = null!; ;

        IsSelection = true;

        try
        {
            point = selection.PickPoint();
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return point != null;
    }

    /// <summary>
    /// 尝试选择一个点
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="snapSettings">选择的对象类型</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryPickPoint(this Selection selection, ObjectSnapTypes snapSettings, out XYZ point)
    {
        point = null!; ;

        IsSelection = true;

        try
        {
            point = selection.PickPoint(snapSettings);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return point != null;
    }

    /// <summary>
    /// 尝试选择一个点
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="statusPrompt">选择时的提示内容</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryPickPoint(this Selection selection, string statusPrompt, out XYZ point)
    {
        point = null!; ;

        IsSelection = true;

        try
        {
            point = selection.PickPoint(statusPrompt);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return point != null;
    }

    /// <summary>
    /// 尝试选择一个点
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="snapSettings">选择的对象类型</param>
    /// <param name="statusPrompt">选择时的提示内容</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryPickPoint(this Selection selection, ObjectSnapTypes snapSettings, string statusPrompt, out XYZ point)
    {
        point = null!; ;

        IsSelection = true;

        try
        {
            point = selection.PickPoint(snapSettings, statusPrompt);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return point != null;
    }


    //-------------------------------------------------------------------------------------------------------------

    /// <summary>
    /// 尝试选择单个点（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryContinuePickPoint(this Selection selection, out XYZ point)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickPoint(out point);
        }
        else
        {
            return selection.TryPickPoint(out point);
        }
    }

    /// <summary>
    /// 尝试选择单个点（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="snapSettings">选择的对象类型</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryContinuePickPoint(this Selection selection, ObjectSnapTypes snapSettings, out XYZ point)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickPoint(snapSettings, out point);
        }
        else
        {
            return selection.TryPickPoint(snapSettings, out point);
        }
    }

    /// <summary>
    /// 尝试选择单个点（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="statusPrompt">选择时的提示内容</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryContinuePickPoint(this Selection selection, string statusPrompt, out XYZ point)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickPoint(statusPrompt, out point);
        }
        else
        {
            return selection.TryPickPoint(statusPrompt, out point);
        }
    }

    /// <summary>
    /// 尝试选择单个点（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="snapSettings">选择的对象类型</param>
    /// <param name="statusPrompt">选择时的提示内容</param>
    /// <param name="point">选择的点，如果函数返回真则不为null</param>
    /// <returns></returns>
    public static bool TryContinuePickPoint(this Selection selection, ObjectSnapTypes snapSettings, string statusPrompt, out XYZ point)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickPoint(snapSettings, statusPrompt, out point);
        }
        else
        {
            return selection.TryPickPoint(snapSettings, statusPrompt, out point);
        }
    }

    /// <summary>
    /// 尝试选择单个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObject(this Selection selection, ObjectType objectType, out Reference reference)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObject(objectType, out reference);
        }
        else
        {
            return selection.TryPickObject(objectType, out reference);
        }
    }

    /// <summary>
    /// 尝试选择单个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObject(this Selection selection, ObjectType objectType, string statusPrompt, out Reference reference)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObject(objectType, statusPrompt, out reference);
        }
        else
        {
            return selection.TryPickObject(objectType, statusPrompt, out reference);
        }
    }

    /// <summary>
    /// 尝试选择单个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObject(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, out Reference reference)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObject(objectType, selectionFilter, out reference);
        }
        else
        {
            return selection.TryPickObject(objectType, selectionFilter, out reference);
        }
    }

    /// <summary>
    /// 尝试选择单个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="reference">选择的元素，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObject(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, string statusPrompt, out Reference reference)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObject(objectType, selectionFilter, statusPrompt, out reference);
        }
        else
        {
            return selection.TryPickObject(objectType, selectionFilter, statusPrompt, out reference);
        }
    }


    #endregion object单选

    #region object多选

    /// <summary>
    /// 尝试选择多个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObjects(this Selection selection, ObjectType objectType, out IList<Reference> references)
    {
        references = new List<Reference>();

        IsSelection = true;

        try
        {
            references = selection.PickObjects(objectType);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return references != null && references.Any();
    }

    /// <summary>
    /// 尝试选择多个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObjects(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, out IList<Reference> references)
    {
        references = new List<Reference>();

        IsSelection = true;

        try
        {
            references = selection.PickObjects(objectType, selectionFilter);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return references != null && references.Any();
    }

    /// <summary>
    /// 尝试选择多个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObjects(this Selection selection, ObjectType objectType, string statusPrompt, out IList<Reference> references)
    {
        references = new List<Reference>();

        IsSelection = true;

        try
        {
            references = selection.PickObjects(objectType, statusPrompt);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return references != null && references.Any();
    }

    /// <summary>
    /// 尝试选择多个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObjects(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, string statusPrompt, out IList<Reference> references)
    {
        references = new List<Reference>();

        IsSelection = true;

        try
        {
            references = selection.PickObjects(objectType, selectionFilter, statusPrompt);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return references != null && references.Any();
    }

    /// <summary>
    /// 尝试选择多个元素
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="pPreSelected">先前选择的对象集。</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryPickObjects(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, string statusPrompt, IList<Reference> pPreSelected, out IList<Reference> references)
    {
        references = new List<Reference>();

        IsSelection = true;

        try
        {
            references = selection.PickObjects(objectType, selectionFilter, statusPrompt, pPreSelected);
        }
        catch
        {
            return false;
        }
        finally
        {
            IsSelection = false;
        }

        return references != null && references.Any();
    }


    //-------------------------------------------------------------------------------------------------------------


    /// <summary>
    /// 尝试选择多个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObjects(this Selection selection, ObjectType objectType, out IList<Reference> references)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObjects(objectType, out references);
        }
        else
        {
            return selection.TryPickObjects(objectType, out references);
        }
    }

    /// <summary>
    /// 尝试选择多个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObjects(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, out IList<Reference> references)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObjects(objectType, selectionFilter, out references);
        }
        else
        {
            return selection.TryPickObjects(objectType, selectionFilter, out references);
        }
    }

    /// <summary>
    /// 尝试选择多个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObjects(this Selection selection, ObjectType objectType, string statusPrompt, out IList<Reference> references)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObjects(objectType, statusPrompt, out references);
        }
        else
        {
            return selection.TryPickObjects(objectType, statusPrompt, out references);
        }
    }

    /// <summary>
    /// 尝试选择多个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObjects(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, string statusPrompt, out IList<Reference> references)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObjects(objectType, selectionFilter, statusPrompt, out references);
        }
        else
        {
            return selection.TryPickObjects(objectType, selectionFilter, statusPrompt, out references);
        }
    }

    /// <summary>
    /// 尝试选择多个元素（可继续选择）
    /// (可继续选择，表示在执行Revit选择元素时，可以继续执行此函数会立即重新执行选择。)
    /// </summary>
    /// <param name="selection">选择器</param>
    /// <param name="objectType">选择的对象类型</param>
    /// <param name="selectionFilter">选择筛选器</param>
    /// <param name="statusPrompt">状态栏显示的消息</param>
    /// <param name="pPreSelected">先前选择的对象集。</param>
    /// <param name="references">选择的元素集合，如果函数返回真则不为null</param>
    /// <returns>真表示选择完成，假表示取消选择或者引发了异常</returns>
    public static bool TryContinuePickObjects(this Selection selection, ObjectType objectType, ISelectionFilter selectionFilter, string statusPrompt, IList<Reference> pPreSelected, out IList<Reference> references)
    {
        if (IsSelection)
        {
            IsSelection = false;
            RevitInputUtils.ActionEsc();
            try { selection.PickPoint(); }
            catch { }
            return selection.TryPickObjects(objectType, selectionFilter, statusPrompt, pPreSelected, out references);
        }
        else
        {
            return selection.TryPickObjects(objectType, selectionFilter, statusPrompt, pPreSelected, out references);
        }
    }

    #endregion object多选
}
